package com.ruoyi.business.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.business.domain.ResearchPlan;
import com.ruoyi.business.request.ApiTrajectoryCreateReq;
import com.ruoyi.business.request.ApiTrajectoryQueryReq;
import com.ruoyi.business.response.ApiTrajectoryRes;
import com.ruoyi.business.service.IResearchPlanService;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.PageResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.RedisUtils;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.ruoyi.business.mapper.TaskUserTrajectoryMapper;
import com.ruoyi.business.domain.TaskUserTrajectory;
import com.ruoyi.business.service.ITaskUserTrajectoryService;

import static com.ruoyi.business.constants.CacheConstant.TRAJECTORY_CACHE_KEY;

/**
 * 调研人员轨迹Service业务层处理
 *
 * @author Eric
 * @date 2024-03-20
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class TaskUserTrajectoryServiceImpl extends ServiceImpl<TaskUserTrajectoryMapper, TaskUserTrajectory> implements ITaskUserTrajectoryService {

    private IResearchPlanService researchPlanService;

    @Override
    public Boolean create(ApiTrajectoryCreateReq req) {
        Long userId = SecurityUtils.getUserId();
        String mapCacheKey = StrUtil.format(TRAJECTORY_CACHE_KEY, req.getResearchPlanId(), userId);
        TaskUserTrajectory taskUserTrajectory = new TaskUserTrajectory();
        String trajectoryId = IdWorker.getIdStr();
        taskUserTrajectory.setId(trajectoryId);
        taskUserTrajectory.setUserId(userId);
        taskUserTrajectory.setLongitude(req.getLongitude());
        taskUserTrajectory.setLatitude(req.getLatitude());
        taskUserTrajectory.setResearchPlanId(req.getResearchPlanId());
        taskUserTrajectory.setCreateBy(SecurityUtils.getUsername());
        taskUserTrajectory.setCreateTime(new Date());
        taskUserTrajectory.setDelFlag("0");
        RedisUtils.setCacheMapValue(mapCacheKey, trajectoryId, taskUserTrajectory);
        return true;
    }

    @Override
    public Boolean sync(Long researchPlanId) {
        Long userId = SecurityUtils.getUserId();
        String mapCacheKey = StrUtil.format(TRAJECTORY_CACHE_KEY, researchPlanId, userId);
        Map<String, TaskUserTrajectory> map = RedisUtils.getCacheMap(mapCacheKey);
        if (MapUtil.isEmpty(map) || map.size() < 2) {
            throw new ServiceException("轨迹过短，不同步数据。");
        }
        TaskUserTrajectory lastTaskUserTrajectory = this.getOne(Wrappers.lambdaQuery(TaskUserTrajectory.class)
                .eq(TaskUserTrajectory::getUserId, userId)
                .eq(TaskUserTrajectory::getResearchPlanId, researchPlanId)
                .orderByDesc(TaskUserTrajectory::getCreateTime)
                .orderByDesc(TaskUserTrajectory::getVersion)
                .last(" LIMIT 1"));
        if (MapUtil.isNotEmpty(map)) {
            List<TaskUserTrajectory> trajectoryList = new ArrayList<>(map.values());
            if (CollUtil.isNotEmpty(trajectoryList)) {
                TaskUserTrajectory newTaskUserTrajectory = trajectoryList.get(trajectoryList.size() - 1);
                long diffSecond = DateUtil.between(newTaskUserTrajectory.getCreateTime(), lastTaskUserTrajectory.getCreateTime(), DateUnit.SECOND);
                Integer maxVer = baseMapper.getMaxVer(researchPlanId, userId);
                if (diffSecond > 10) {
                    for (TaskUserTrajectory taskUserTrajectory : trajectoryList) {
                        taskUserTrajectory.setVersion(maxVer + 1);
                    }
                } else {
                    for (TaskUserTrajectory taskUserTrajectory : trajectoryList) {
                        taskUserTrajectory.setVersion(maxVer);
                    }
                }
            }
            if (baseMapper.insertBatchSomeColumn(trajectoryList) == trajectoryList.size()) {
                RedisUtils.deleteObject(mapCacheKey);
            } else {
                throw new ServiceException("同步轨迹失败");
            }
        }
        return true;
    }

    @Override
    public List<List<BigDecimal>> getTrajectoryList(Long researchPlanId, Integer version) {
        List<TaskUserTrajectory> list = list(Wrappers.lambdaQuery(TaskUserTrajectory.class)
                .eq(TaskUserTrajectory::getUserId, SecurityUtils.getUserId())
                .eq(TaskUserTrajectory::getResearchPlanId, researchPlanId)
                .eq(TaskUserTrajectory::getVersion, version)
                .orderByAsc(BaseEntity::getCreateTime));
        List<List<BigDecimal>> resultList = Lists.newArrayList();
        list.forEach(trajectory -> {
            List<BigDecimal> pointArray = Lists.newArrayList();
            pointArray.add(trajectory.getLongitude());
            pointArray.add(trajectory.getLatitude());
            resultList.add(pointArray);
        });

        return resultList;
    }


    @Override
    public Map<String, List<List<BigDecimal>>> getTrajectoryListAdmin(Long researchPlanId, Long userId, Integer version) {
        LambdaQueryWrapper<TaskUserTrajectory> lambdaQueryWrapper = Wrappers.lambdaQuery(TaskUserTrajectory.class)
                .eq(TaskUserTrajectory::getResearchPlanId, researchPlanId)
                .orderByAsc(BaseEntity::getCreateTime);
        if (userId != null) {
            lambdaQueryWrapper.eq(TaskUserTrajectory::getUserId, userId);
        }
        if (version != null) {
            lambdaQueryWrapper.eq(TaskUserTrajectory::getVersion, version);
        }

        List<TaskUserTrajectory> list = list(lambdaQueryWrapper);
        Map<String, List<TaskUserTrajectory>> map = Maps.newHashMap();
        if (CollUtil.isNotEmpty(list)) {
            //根据userId和version字段进行分组
            map = list.stream().collect(
                    Collectors.groupingBy(
                            trajectory -> trajectory.getUserId() + "_" + trajectory.getVersion()
                    ));

        }
        Map<String, List<List<BigDecimal>>> resultMap = Maps.newHashMap();
        if (MapUtil.isNotEmpty(map)) {
            map.forEach((key, trajectoryList) -> {
                List<List<BigDecimal>> resultList = Lists.newArrayList();
                trajectoryList.forEach(trajectory -> {
                    List<BigDecimal> pointArray = Lists.newArrayList();
                    pointArray.add(trajectory.getLongitude());
                    pointArray.add(trajectory.getLatitude());
                    resultList.add(pointArray);
                });
                resultMap.put(key, resultList);
            });
        }

//        List<List<BigDecimal>> resultList = Lists.newArrayList();
//        list.forEach(trajectory -> {
//            List<BigDecimal> pointArray = Lists.newArrayList();
//            pointArray.add(trajectory.getLongitude());
//            pointArray.add(trajectory.getLatitude());
//            resultList.add(pointArray);
//        });

        return resultMap;
    }

    @Override
    public Map<Integer, List<TaskUserTrajectory>> getTrajectoryListMap(Long researchPlanId) {
        List<TaskUserTrajectory> list = list(Wrappers.lambdaQuery(TaskUserTrajectory.class)
                .eq(TaskUserTrajectory::getUserId, SecurityUtils.getUserId())
                .eq(TaskUserTrajectory::getResearchPlanId, researchPlanId)
                .orderByAsc(BaseEntity::getCreateTime));
        Map<Integer, List<TaskUserTrajectory>> listMap = list.stream().collect(Collectors.groupingBy(TaskUserTrajectory::getVersion));
        return listMap;
    }

    @Override
    public PageResult<ApiTrajectoryRes> pageTrajectory(ApiTrajectoryQueryReq req) {
        req.setUserId(SecurityUtils.getUserId());
        PageUtils.startPage();
        List<ApiTrajectoryRes> resList = baseMapper.pageTrajectory(req);
        return PageResult.empty(resList);
    }
}
